from tool_class.db_connection import DatabaseOperations
from tool_class.rule_processing_base import RuleProcessingBase
import datetime
import traceback
class RuleProcessing(RuleProcessingBase):

    def __init__(self, regulation_conn,parity_conn):
        self.parity_conn = parity_conn
        super().__init__(regulation_conn)

    def get_before_processing(self, regulation,table_name,work_id,channel,action_detail = None):
        condition = [item for item in regulation if item['detail_type'] == '0']
        channelIds = channel.replace("[","(").replace("]",")")
        regulation_condition = self.join_condition(condition)
        sql = f"select new_id from {table_name} where work_id = '{work_id}' and channel_id in {channelIds} and ({regulation_condition})"
        #处理补充动作时传action_detail，需要将补充的字段加到sql中
        if action_detail:
            for field in action_detail:
                sql += f" and {field} is null"
        print("before_sql---->",sql)
        results = self.parity_conn.execute_query(sql)
        #如果results没有数据是，则返回None
        if not results:
            return None
        strings = [itme["new_id"] for itme in results]
        before_processing_data = "(" + ",".join(f'"{s}"' for s in strings) + ")"
        # print("before_processing_data---->", before_processing_data)
        return before_processing_data

    def get_after_processing(self, work_id,table_name,newIds,*args,expression = "in"):
        query_fields = [f"{table_name}.{field}" for field in args]
        query_field = ",".join(query_fields)
        sql = f"select {query_field} from {table_name} where work_id = '{work_id}' and new_id {expression} {newIds}"
        # print("get_after_processing-sql---->", sql)
        results = self.parity_conn.execute_query(sql)
        if not results:
            return None
        return results

    def check_conditions(self,expected_value, result_values, expression_type, reverse=False):
        check_func = lambda x, y: x != y if reverse else x == y
        if expression_type == "==":
            return all(check_func(expected_value, value) for value in result_values)
        elif expression_type == "in":
            return all(check_func(expected_value in value, True) for value in result_values) if not reverse else all(
                check_func(expected_value not in value, True) for value in result_values)
        else:
            print(f"不支持的表达式类型: {expression_type}")
            return False

    def check_is_lost(self,front_table_name,after_table_name,work_id):
        sql = f"""SELECT
                        * 
                    FROM
                        {front_table_name} a
                        LEFT JOIN {after_table_name} b ON a.work_id = b.work_id 
                    WHERE
                        a.work_id = "{work_id}" 
                        AND a.work_id IS NULL
                """
        result = self.parity_conn.execute_query(sql)
        print("result---->", result)
        return False if result else True

    def assert_modify_action(self, regulation,work_id,regulation_id,channel,action_detail = None):
        # 获取需要修改的字段和值
        modify_fields = [ item['field_name'] for item in regulation if item['detail_type'] == '1']
        modify_fields.append("hit_rules")
        # print("modify_fields---->", modify_fields[-1:])
        expect_result = {}
        for item in regulation:
            if item['detail_type'] == '1':
                expect_result[item['field_name']] = item['condition_detail']
        before_data_newIds = self.get_before_processing(regulation, "ays_api_reslt_data_analysis", work_id,channel,action_detail=action_detail)
        if not before_data_newIds: #如果before_data_newIds为空，则返回True,代表该批数据没有命中该规则
            return True
        after_data = self.get_after_processing(work_id, "ays_post_process_data", before_data_newIds,*modify_fields[0:-1])
        reverse_after_data = self.get_after_processing(work_id, "ays_post_process_data", before_data_newIds,*modify_fields[0:-1],expression = "not in")
        hit_rules = self.get_after_processing(work_id, "ays_post_process_data", before_data_newIds,*modify_fields[-1:])
        new_hit_rules = [item['hit_rules'] for item in hit_rules]
        if not after_data or not hit_rules: #如果after_data或者hit_rules为空，则返回False
            return False
        # print("new_hit_rules---->", new_hit_rules)
        # print("after_data---->", after_data)
        # print(self.check_conditions(expect_result, after_data, "=="))
        # print(self.check_conditions(expect_result, reverse_after_data, "==",reverse=True))
        # print(self.check_conditions(regulation_id, new_hit_rules, "in"))
        # print(self.check_is_lost("ays_api_reslt_data_analysis", "ays_post_process_data", work_id))
        return self.check_conditions(expect_result, after_data, "==") \
               and self.check_conditions(expect_result, reverse_after_data, "==",reverse=True) \
               and self.check_conditions(regulation_id, new_hit_rules, "in")\
               and self.check_is_lost("ays_api_reslt_data_analysis", "ays_post_process_data", work_id)


    def assert_replenish_action(self, regulation,work_id,regulation_id,channel,action_detail):
        # 补充动作需要把补充的字段加到sql中，所以传入action_detail
        return self.assert_modify_action(regulation,work_id,regulation_id,channel,action_detail=action_detail)

    def assert_filtration_action(self, regulation,work_id,regulation_id,channel):
        before_data_newIds = self.get_before_processing(regulation, "ays_api_reslt_data_analysis", work_id,channel)
        if not before_data_newIds: #如果before_data_newIds为空，则返回True,代表该批数据没有命中该规则
            return True
        after_data = self.get_after_processing(work_id, "ays_post_process_data", before_data_newIds,*("hit_rules","abandon"))
        if not after_data: #如果after_data为空，则返回False
            return False
        new_hit_rules = [item['hit_rules'] for item in after_data]
        isabandon_list = [item['abandon'] for item in after_data]
        return self.check_conditions(regulation_id, new_hit_rules, "in") \
               and self.check_conditions(1, isabandon_list, "==",reverse=True) \
               and  self.check_conditions(1, isabandon_list, "==") \
               and self.check_is_lost("ays_api_reslt_data_analysis", "ays_post_process_data", work_id)

    def perform_the_action(self, regulation_type,regulation,work_id,regulation_id,channel):
        print("regulation_type", regulation_type)
        try:
            action_result = {
                "R01": self.assert_modify_action,
                "R03": self.assert_replenish_action,
                "R05": self.assert_filtration_action,
            }
            func = action_result[regulation_type]
            if regulation_type == "R03":
                action_detail = [item['field_name'] for item in regulation]
                print(action_detail,"----action_detail")
                return func(regulation,work_id,regulation_id,channel,action_detail)
            return func(regulation,work_id,regulation_id,channel)
        #捕获校验过程中可能发生的异常，如果有异常，返回False，表示当前校验的规则执行失败
        except Exception as e:
            print(traceback.format_exc())
            print(e)
            return False

    def weight_rule_verification(self,work_id):
        regulation_list = self.get_regulation_list()
        print(regulation_list,"----regulation_list")
        #对规则进行排序，权重高的排在前面，权重相同时按时间倒序
        sorted_regulation = sorted(regulation_list, key=lambda x: (-x['regulation_weight'], -x['create_time'].timestamp()))
        result_list = []
        for rule in sorted_regulation:
            check_result = self.perform_the_action(rule['regulation_type'], rule['detail_list'],work_id,rule['regulation_id'],rule['channel'])
            result_list.append({rule['regulation_id']: check_result})
        # print(result_list,"----result_list")
        #处理规则之间的影响
        for i in range(len(result_list)):
            # print(result_list[i],"----result_list[i]")
            # print(sorted_regulation[i]['regulation_id'],"----sorted_regulation[i]['regulation_id']")
            regulation = sorted_regulation[i]
            # 当前规则执行失败，且是最后一条规则还不是过滤动作，则直接返回False
            if not result_list[i][regulation['regulation_id']] and i == len(result_list)-1 and regulation['regulation_type'] != "R05":
                print("最后一条规则执行失败",regulation['regulation_id'])
                break
            # 当前规则执行失败，且还不是过滤动作，但后面还有规则，判断后面规则是否对这条失败规则有影响
            elif not result_list[i][regulation['regulation_id']] and regulation['regulation_type'] != "R05":
                #获取当前校验失败规则的动作字段
                action_detail = [detail['field_name'] for detail in regulation['detail_list'] if detail['detail_type'] == '1']
                #循环后面的规则
                for j in range(i+1, len(result_list)):
                    posterior_rule = sorted_regulation[j]
                    # 判断后面的规则是不是修改,且该规则是通过的，是的话执行下面代码
                    if posterior_rule['regulation_type'] == "R01" and result_list[j][posterior_rule['regulation_id']]:
                        posterior_action_detail = [detail['field_name'] for detail in posterior_rule['detail_list'] if detail['detail_type'] == '1']
                        # 判断当前规则的修改字段是否在后面规则的修改字段,是的话，将后面规则的校验结果设置为True
                        for action_detail in action_detail:
                            if action_detail in posterior_action_detail:
                                #将当前规则的校验结果设置为True
                                result_list[i][list(result_list[i].keys())[0]] = True
        print(result_list, "----result_list")
        return result_list



if __name__ == '__main__':
    regulation_conn = DatabaseOperations()
    regulation_conn.connect("富通东方", "mysql_query")
    parity_conn = DatabaseOperations()
    parity_conn.connect("慧思拓测试库", "starrockets_dev_query")
    rule_obj = RuleProcessing(regulation_conn,parity_conn)
    # rule = rule_obj.get_regulation_list()[4]
    # print(rule,"----rule")
    # result = rule_obj.get_before_processing(rule,"ays_api_reslt_data_analysis","2b05320b578eed29ba6de5389ec7fb71",("car_series_name","scenario"), *("work_id", "new_id"))
    # print(result)
    # result1 = rule_obj.assert_modify_action(rule['detail_list'],"2b05320b578eed29ba6de5389ec7fb71",rule['regulation_id'])
    # print(result1,"----result1")
    result_values = [{'scenario': "None", 'car_series_name': "2b05320b578eed29ba6de5389ec7fb71"},
                     {'scenario': "None", 'car_series_name': "2b05320b578eed29ba6de5389ec7fb71"},{'scenario': "None", 'car_series_name': "2b05320b578eed29ba6de5389ec7fb71"}]
    expected_value = {'scenario': "None", 'car_series_name': "2b05320b578eed29ba6de5389ec7fb71"}
    # result = rule_obj.check_conditions(expected_value, result_values, "==",reverse=True)
    hit_rules = "123"
    new_hit_rules = ["1232","456123","789123"]
    # result = rule_obj.check_conditions(hit_rules, new_hit_rules, "in")
    # print(result,"----result")
    # result3=rule_obj.perform_the_action("R01", rule['detail_list'], "2b05320b578eed29ba6de5389ec7fb71", rule['regulation_id'])
    # print(result3,"----result3")
    result2 = rule_obj.check_is_lost("ays_api_reslt_data_analysis", "ays_post_process_data", "in2b05320b578eed29ba6de5389ec7fb71")

    data = [{'create_time': datetime.datetime(2024, 9, 6, 16, 40, 19),
             'regulation_weight': 100},
            {'create_time': datetime.datetime(2024, 9, 6, 16, 31, 2),
             'regulation_weight': 100},{'create_time': datetime.datetime(2024, 9, 6, 16, 31, 2),
             'regulation_weight': 700}]

    sorted_data = sorted(data, key=lambda x: (-x['regulation_weight'], -x['create_time'].timestamp()))
    rule_obj.weight_rule_verification("02cc8aba6b0d453239c60cbd7f6c0910")
